// Kokomi.js - Three.js 组件框架
import * as kokomi from "kokomi.js";
// Three.js - 3D 渲染引擎
import * as THREE from "three";

import type Experience from "../Experience";

/**
 * 芙宁娜角色组件（隐藏彩蛋模式）
 * 在 URL 包含 #furina 时启用
 * 显示芙宁娜角色坐在车内驾驶的动画
 */
export default class Furina extends kokomi.Component {
  declare base: Experience; // Experience 实例引用
  model: THREE.Group; // 模型容器
  realModel: THREE.Group; // 实际的芙宁娜模型
  modelParts: THREE.Object3D[]; // 模型部件数组
  mixer: THREE.AnimationMixer; // 动画混合器
  actions: Record<string, THREE.AnimationAction>; // 动画动作字典
  currentAction: THREE.AnimationAction | null; // 当前播放的动作
  isPaused: boolean; // 是否暂停动画
  
  constructor(base: Experience) {
    super(base);

    // 创建一个空的容器组
    const model = new THREE.Group();
    this.model = model;

    // 加载芙宁娜驾驶动画模型（FBX 格式）
    // const realModel = this.base.am.items["furina"] as THREE.Group;
    const realModel = this.base.am.items["driving"] as THREE.Group;
    this.realModel = realModel;

    // 将实际模型添加到容器
    this.model.add(this.realModel);

    // 将模型场景树展平为数组
    const modelParts = kokomi.flatModel(this.realModel);
    // kokomi.printModel(modelParts); // 调试用：打印模型结构
    this.modelParts = modelParts;

    // 处理模型（设置位置、缩放、材质等）
    this.handleModel();

    // 创建动画混合器
    const mixer = new THREE.AnimationMixer(this.model);
    this.mixer = mixer;

    // 初始化动作字典
    this.actions = {};

    // 当前无动作
    this.currentAction = null;

    // 添加驾驶动画
    this.addAction("driving", "driving");

    // 播放驾驶动画
    this.playAction("driving");

    // 更新动画到第 1 帧（初始化姿势）
    this.mixer.update(1);
    // 默认暂停动画（加速时才播放）
    this.isPaused = true;
  }
  /**
   * 将芙宁娜模型添加到场景
   */
  addExisting() {
    this.container.add(this.model);
  }
  /**
   * 每帧更新
   * 如果未暂停，则更新动画
   */
  update(): void {
    // 如果动画已暂停，不更新
    if (this.isPaused) {
      return;
    }

    // 根据帧间隔时间更新动画
    this.mixer.update(this.base.clock.deltaTime);
  }
  /**
   * 处理模型：设置位置、缩放、旋转和材质
   */
  handleModel() {
    // 设置模型缩放（统一缩小到 0.074 倍）
    this.model.scale.setScalar(0.074);

    // 旋转 90 度（让角色朝向正确方向）
    this.model.rotation.y = Math.PI * 0.5;

    // 设置模型位置（坐在车内驾驶室）
    this.model.position.set(0.225, 0.15, -0.4);

    // 遍历模型所有部件，将 Phong 材质替换为 Basic 材质
    // @ts-ignore
    this.modelParts.forEach((item: THREE.Mesh) => {
      if (item.isMesh) {
        // 如果是 Phong 材质，转换为 Basic 材质（更简单，无光照计算）
        if ((item.material as THREE.MeshPhongMaterial).isMeshPhongMaterial) {
          const newMat = new THREE.MeshBasicMaterial({
            transparent: true, // 启用透明
            // @ts-ignore
            map: item.material.map || null, // 保留原有的贴图
            // color: new THREE.Color("#666666"), // 可选：设置颜色
          });
          item.material = newMat;
        }
      }
    });
  }
  /**
   * 添加动画动作到字典
   * @param assetName - 资源名称
   * @param name - 动作名称
   */
  addAction(assetName: string, name: string) {
    // 从资源管理器获取动画数据
    const animation = (this.base.am?.items[assetName] as THREE.Group)
      .animations[0];
    // 创建动画动作
    const action = this.mixer.clipAction(animation);
    // 存储到字典
    this.actions[name] = action;
  }
  /**
   * 播放指定名称的动作
   * @param name - 动作名称
   * @returns 播放的动作
   */
  playAction(name: string) {
    // 如果有当前动作，淡出
    if (this.currentAction) {
      this.currentAction.fadeOut(0.5);
    }
    // 获取目标动作
    const action = this.actions[name];
    // 设置权重为 1（完全显示）
    action.weight = 1;
    // 重置并淡入播放
    action.reset().fadeIn(0.5).play();
    // 更新当前动作
    this.currentAction = action;
    return action;
  }
  /**
   * 设置模型颜色
   * 用于动画过渡时改变角色颜色
   * @param color - Three.js 颜色对象
   */
  setColor(color: THREE.Color) {
    // @ts-ignore
    this.modelParts.forEach((item: THREE.Mesh) => {
      if (item.isMesh) {
        const mat = item.material as THREE.MeshBasicMaterial;
        // 设置材质颜色
        mat.color.set(color);
      }
    });
  }
  /**
   * 暂停动画（减速时调用）
   */
  pause() {
    this.isPaused = true;
  }
  
  /**
   * 恢复动画（加速时调用）
   */
  drive() {
    this.isPaused = false;
  }
}
